package main;

import java.util.ArrayList;
import java.util.Collection;

import main.listeners.ListenerClearer;
import main.listeners.ListenerContainer;
import main.listeners.listenerClasses.GameListener;
import main.listeners.listenerClasses.LanguageListener;
import main.listeners.listenerClasses.PauseListener;
import main.listeners.listenerClasses.SettingsListener;
import main.listeners.listenerClasses.gui.ChatActivatedEvent;
import main.listeners.listenerClasses.gui.ConsoleToggleEvent;
import main.listeners.listenerClasses.gui.GUIListener;
import main.listeners.listenerClasses.gui.IngameChangedEvent;
import main.listeners.listenerClasses.gui.LoginListener;
import main.listeners.listenerClasses.gui.ScoreBoardToggleEvent;
import main.listeners.listenerClasses.gui.SpawnMenuChangedEvent;
import main.listeners.listenerClasses.loading.LoadingAbortedEvent;
import main.listeners.listenerClasses.loading.LoadingListener;
import main.listeners.listenerClasses.loading.LoadingStartedEvent;
import main.listeners.listenerClasses.loading.LoadingStoppedEvent;
import map.Map;

import settings.GraphicSettings;
import fileHandling.language.LanguageLoader;
import gameStates.absGamesStates.gui.AbsChatState;
import gameStates.absGamesStates.network.AbsClientState;
import gameStates.absGamesStates.network.AbsNetworkState;
import gameStates.absGamesStates.network.AbsServerState;
import gameStates.gui.LoadingState;

public abstract class AbsInitGame {
	
	protected AbsClientState clientState;
	protected AbsServerState serverState;
	
	protected Map currentMap;
	
	protected boolean spawnMenuWasOpen, ingame, isServer, isChangingGraphics, wasIngameBeforeGraphics;
	protected boolean creatingMenuState, isPaused;
	
	protected ListenerContainer settingsListeners;
	protected ListenerContainer languageListeners;
	protected ListenerContainer loadingListeners;
	protected ListenerContainer guiListeners;
	protected ListenerContainer gameListeners;
	protected ListenerContainer loginListeners;
	protected ListenerContainer pauseListeners;
	
	protected ListenerClearer languageListenerClearer;
	protected Collection<LanguageListener> menuLanguageListeners;
	
	public AbsInitGame(AbsClientState clientState, AbsServerState serverState) {
		this.clientState = clientState;
		this.serverState = serverState;
		
		gameListeners = new ListenerContainer(GameListener.class);
		guiListeners = new ListenerContainer(GUIListener.class);
		loadingListeners = new ListenerContainer(LoadingListener.class);
		
		settingsListeners = new ListenerContainer(SettingsListener.class);
		languageListeners = new ListenerContainer(LanguageListener.class);
		
		pauseListeners = new ListenerContainer(PauseListener.class);
		
		loginListeners = new ListenerContainer(LoginListener.class);
		
		menuLanguageListeners = new ArrayList<LanguageListener>();
		languageListenerClearer = new ListenerClearer(languageListeners);
	}
	
	public abstract void init(String[] args);
	
	public abstract void logout();
	
	public abstract void login(String profileName, boolean autoLogin);
	
	public abstract void endCurrentGame();
	
	public abstract String getThisIP();
	
	public abstract void initNewGame(boolean isServer, GameCycle gameCycle);
	
	public abstract void exit();
	
	public abstract void changeGraphicSettings(GraphicSettings oldConfig);
		
	public abstract void abortLoadingThread();
	
	public abstract void changeSoundSettings();
	
	public boolean isChangingGraphics() { return isChangingGraphics; }
	
	public void addPauseListener(PauseListener l) {
		pauseListeners.addListener(l);
	}
	
	public void removePauseListener(PauseListener l) {
		pauseListeners.removeListener(l);
	}
	
	public void changeChatState(AbsChatState chatState) {
		guiListeners.callMethod(GUIListener.CHATACTIVATED, new ChatActivatedEvent(chatState));
	}
	
	public void changeCommonSettings() {
		LanguageLoader.loadAllLanguageFiles();
		
		changeLanguage();
		
		settingsListeners.callMethod(SettingsListener.COMMONSETTINGSCHANGED);
	}
	
	public void changeControlSettings() {
		settingsListeners.callMethod(SettingsListener.CONTROLSETTINGSCHANGED);
	}
	
	public void gameStarted() {
		gameListeners.callMethod(GameListener.GAMESTARTED);
	}
	
	public void gameFinished() {
		gameListeners.callMethod(GameListener.GAMEFINISHED);
	}
	
	public void gameDestroyed() {
		gameListeners.callMethod(GameListener.GAMEDESTROYED);
	}
	
	public void changeIngame(boolean newIngame) {
		if(ingame == newIngame) return;
		
		ingame = newIngame;
		
		IngameChangedEvent event = new IngameChangedEvent(ingame, spawnMenuWasOpen);
		guiListeners.callMethod(GUIListener.INGAMECHANGED, event);
	}
	
	public void toggleSpawnMenu() {
		assert(isIngame());
		
		spawnMenuWasOpen = !spawnMenuWasOpen;
		
		guiListeners.callMethod(GUIListener.SPAWNMENUCHANGED, new SpawnMenuChangedEvent(spawnMenuWasOpen));
	}
	
	public void toggleScoreBoard(boolean enable) {
		assert(isIngame());
		
		ScoreBoardToggleEvent event = new ScoreBoardToggleEvent(enable, spawnMenuWasOpen);
		guiListeners.callMethod(GUIListener.SCOREBOARDTOGGLED, event);
	}
	
	public void togglePause() {
		isPaused = !isPaused;
		
		pauseListeners.callMethod(PauseListener.PAUSE, Boolean.valueOf(isPaused));
	}
	
	public void addGameListener(GameListener l) { gameListeners.addListener(l); }
	
	public void removeGameListener(GameListener l) { gameListeners.removeListener(l); }
	
	public void addSettingsListener(SettingsListener l) { settingsListeners.addListener(l); }
	
	public void removeSettingsListener(SettingsListener l) { settingsListeners.removeListener(l); }
	
	public void addLoginListener(LoginListener l) { loginListeners.addListener(l); }
	
	public void removeLoginListener(LoginListener l) { loginListeners.removeListener(l); }
	
	public boolean isServer() { return isServer; }
	
	public boolean isIngame() { return ingame; }
		
	public void toggleConsole(boolean active) {
		guiListeners.callMethod(GUIListener.CONSOLETOGGLED, new ConsoleToggleEvent(active));
	}
	
	public void loadingStarted(LoadingState loadingState) {
		loadingListeners.callMethod(LoadingListener.LOADINGSTARTED, new LoadingStartedEvent(loadingState));
	}
	
	public void loadingAborted(LoadingState loadingState) {
		loadingListeners.callMethod(LoadingListener.LOADINGABORTED, new LoadingAbortedEvent(loadingState));
	}
	
	public void loadingStopped(LoadingState loadingState) {
		loadingListeners.callMethod(LoadingListener.LOADINGSTOPPED, new LoadingStoppedEvent(loadingState));
	}
	
	public void setCurrentMap(Map scen) { currentMap = scen; }
	
	public Map getCurrentMap() { return currentMap; }
	
	public AbsClientState getClientState() { return clientState; }
	
	public AbsServerState getServerState() { return serverState; }
	
	public AbsNetworkState getNetworkState() {
		return (isServer() ? serverState : clientState);
	}
	
	protected void clearLanguageListeners() {
		languageListenerClearer.clear();
	}
	
	public void addLanguageListener(LanguageListener l) {
		languageListenerClearer.addListener(l);
		if(creatingMenuState) menuLanguageListeners.add(l);
	}
	
	public void changeLanguage() {
		languageListeners.callMethod(LanguageListener.LANGUAGECHANGED);
	}
	
	public void setChangingGraphics(boolean b) {
		isChangingGraphics = b;
		if(!isChangingGraphics && wasIngameBeforeGraphics) changeIngame(true);
	}
	
	public void addGUIListener(GUIListener l) { guiListeners.addListener(l); }
	
	public void removeGUIListener(GUIListener l) { guiListeners.removeListener(l); }
	
	public ListenerClearer createNewListenerClearer(Class<?> listenerClass) {
		if(listenerClass == GUIListener.class) return new ListenerClearer(guiListeners);
		if(listenerClass == GameListener.class) return new ListenerClearer(gameListeners);
		if(listenerClass == SettingsListener.class) return new ListenerClearer(settingsListeners);
		if(listenerClass == LoadingListener.class) return new ListenerClearer(loadingListeners);
		if(listenerClass == LanguageListener.class) return new ListenerClearer(languageListeners);
		if(listenerClass == LoginListener.class) return new ListenerClearer(loginListeners);
		if(listenerClass == PauseListener.class) return new ListenerClearer(pauseListeners);
		return null;
	}
}